﻿using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using WebAPITest.Models;
using WebAPITest.Models.Database;
using WebAPITest.service;

namespace WebAPITest.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class RedisController : ControllerBase
    {
        private readonly IDatabase _redis;
        private readonly WebEnterpriseIIContext _db;
        private readonly IUserService _userService;
        public RedisController(RedisHelper client, WebEnterpriseIIContext db, IUserService userService)
        {
            _db = db;
            //创建Redis连接对象
            _redis = client.GetDatabase();
            _userService = userService;
        }


        /// <summary>
        /// 
        /// </summary>
        [HttpGet]
        public void SetRedisCache()
        {
            _redis.StringSet("RedisCache", "6666");
        }

        /// <summary>
        /// 
        /// </summary>
        [HttpGet]
        public void RedisString()
        {
            var str = "广东工程职业技术学院";
            //写入String的值
            _redis.StringSet("StringCache", str);

            //获取String缓存的值
            var value = _redis.StringGet("StringCache");

            //追加字符
            _redis.StringAppend("StringCache", "666");

            //写入数据 5小时5分钟5秒 后过期
            _redis.StringSet("StringCache1", 1, new TimeSpan(5, 5, 5));

            //key为StringCache1的值自增1
            _redis.StringIncrement("StringCache1");

            //key为StringCache1的值增加10
            _redis.StringIncrement("StringCache1", 10);

            //key为StringCache1的值自减1
            _redis.StringDecrement("StringCache1");

            //key为StringCache1的值减少5
            _redis.StringDecrement("StringCache1", 5);
        }


        [HttpGet]
        public void StringTest()
        {
            //添加key为goodName,value为"华为手机"的string类型数据
            _redis.StringSet("goodName", "华为手机");
            //获取key为goodName的数据x
            var value = _redis.StringGet("goodName");
            //把key为goodName的数据，value设置为"小米手机"，并且设置过期时间为20秒
            _redis.StringSet("goodName", "小米手机", new TimeSpan(0, 0, 20));
            //在key为goodName的值后面添加字符串"666"
            _redis.StringAppend("goodName", "666");
            //查看key为goodName的值长度
            _redis.StringLength("goodName");
        }

        [HttpGet]
        public void RedisHash()
        {
            var hashKey = "testhashkey";
            //hash写入单个数据
            _redis.HashSet(hashKey, "name", "刘备");

            //hash写入多个数据
            var hashEntrys = new HashEntry[] { new HashEntry("num", "1406200115"), new HashEntry("class", "软件A班"), new HashEntry("age", 18) };
            _redis.HashSet(hashKey, hashEntrys);

            //hash获取数据
            var value1 = _redis.HashGet(hashKey, "name");

            //hash获取所有数据
            var value2 = _redis.HashGetAll(hashKey);

            //判断hash的属性是否存在
            var value3 = _redis.HashExists(hashKey, "name");

            //hash的属性值自增，自减
            var value4 = _redis.HashIncrement(hashKey, "age");
            value4 = _redis.HashDecrement(hashKey, "age");

            //hash删除某个属性
            _redis.HashDelete(hashKey, "class");
        }

        [HttpGet]
        public void HashTest()
        {
            //把以上json数据使用hash的数据格式添加redis数据库中，key为"liubeiinfo"
            _redis.HashSet("liubeiinfo", "name", "刘备");
            _redis.HashSet("liubeiinfo", "class", "软件技术X班");
            _redis.HashSet("liubeiinfo", "school", "广东工程职业技术学院");
            _redis.HashSet("liubeiinfo", "age", "1862");
            _redis.HashSet("liubeiinfo", "num", "1406200228");

            //获取显示上述hash数据所有属性
            var data = _redis.HashGetAll("liubeiinfo");
            //修改学号num的值为"1406200230"
            _redis.HashSet("liubeiinfo", "num", "1406200230");

            //查询修改后学号的值
            var num = _redis.HashGet("liubeiinfo", "num");

        }

        [HttpGet]
        public void RedisList()
        {
            var listkey = "testlistkey1";
            //左侧推入单个元素
            _redis.ListLeftPush(listkey, "刘备");
            //左侧推入多个元素
            var redisValues1 = new RedisValue[] { "张飞", "关羽" };
            _redis.ListLeftPush(listkey, redisValues1);
            //右侧同理
            _redis.ListRightPush(listkey, "马超");
            var redisValues2 = new RedisValue[] { "赵云", "马岱" };
            _redis.ListRightPush(listkey, redisValues2);

            //获取所有元素
            _redis.ListRange(listkey, 0, -1);

            //获取指定索引的元素
            _redis.ListGetByIndex(listkey, 2);

            //从左边取出并一个并删除元素
            _redis.ListLeftPop(listkey);
            //从右边取出并一个并删除元素
            _redis.ListRightPop(listkey);
        }

        //[
        //    "刘备",//1
        //    "关羽",//2
        //    "张飞",//3
        //    "赵云",//4
        //    "马超",//5
        //    "曹操",//6
        //    "吕布" //7
        //]
        [HttpGet]
        public void ListTest()
        {
            // _redis.ListLeftPush()
            //4 3 2 1
            // _redis.ListRightPush()
            //1 2 3 4
            //把以上json数据列表使用list数据格式以上述指定顺序添加到redis数据库中,key为"userList"
            var redisValues1 = new RedisValue[] { "刘备", "关羽", "张飞", "赵云", "马超", "曹操", "吕布" };
            _redis.ListRightPush("userList", redisValues1);

            //查看目前列表数据并核对顺序 -1代表全部
            var list = _redis.ListRange("userList", 0, -1);

            //再赵云和马超中间加入"黄盖"
            _redis.ListInsertBefore("userList", "马超", "黄盖");

            //查看目前列表数据
            list = _redis.ListRange("userList", 0, -1);
        }

        [HttpGet]
        public void RedisSet()
        {
            var setkey = "testsetkey1";
            //添加单个元素
            _redis.SetAdd(setkey, "刘备");
            //添加多个元素
            var redisValues1 = new RedisValue[] { "张飞", "关羽", "周瑜" };
            _redis.SetAdd(setkey, redisValues1);
            //移除某个元素
            _redis.SetRemove(setkey, "刘备");

            //获取所有成员
            var value1 = _redis.SetMembers(setkey);
            //随机获取一个元素
            var value2 = _redis.SetRandomMember(setkey);
            //随机获取多个元素
            var value3 = _redis.SetRandomMembers(setkey, 2);
            //判断是否包含某个元素
            _redis.SetContains(setkey, "马超");

            var setkey2 = "testsetkey2";
            var redisValues2 = new RedisValue[] { "张飞", "关羽", "马超", "赵云", "曹操", "黄盖" };
            _redis.SetAdd(setkey2, redisValues2);
            //获取两个集合的交集
            var value5 = _redis.SetCombine(SetOperation.Intersect, setkey, setkey2);
            //获取两个集合的差集
            var value4 = _redis.SetCombine(SetOperation.Difference, setkey, setkey2);
            //获取两个集合的并集
            var value6 = _redis.SetCombine(SetOperation.Union, setkey, setkey2);
        }

        ////以下为刘备同学关注的用户Id列表
        //[
        //    1214,
        //    5651,
        //    5654,
        //    2668,
        //    9595,
        //    9955,
        //]
        ////以下为张飞同学关注的用户Id列表
        //[
        //    5985,
        //    5651,
        //    5654,
        //    6555,
        //    9595,
        //    9998,
        //]
        [HttpGet]
        public void SetTest()
        {
            //把刘备同学关注的用户Id列表使用Set数据类型添加到Redis数据库中，设置key为"followList_liu"
            var redisValues1 = new RedisValue[] { "1214", "5651", "5654", "2668", "9595", "9955" };
            _redis.SetAdd("followList_liu", redisValues1);
            //把张飞同学关注的用户Id列表使用Set数据类型添加到Redis数据库中，设置key为"followList_zhang"
            var redisValues2 = new RedisValue[] { "5985", "5651", "5654", "6555", "9595", "9998" };
            _redis.SetAdd("followList_zhang", redisValues2);

            //使用set类型数据命令获取刘备同学和张飞同学共同关注的人 = 交集 
            var list = _redis.SetCombine(SetOperation.Intersect, "followList_liu", "followList_zhang");
        }


        [HttpGet]
        public void RedisZSet()
        {
            var zsetkey = "testzsetkey1";
            //添加单个元素
            _redis.SortedSetAdd(zsetkey, "刘备", 50);
            //添加多个元素
            var values = new[]
                { new SortedSetEntry("马超", 23), new SortedSetEntry("赵云", 50), new SortedSetEntry("关羽", 56) };
            _redis.SortedSetAdd(zsetkey, values);
            //移除某个元素
            _redis.SortedSetRemove(zsetkey, "马超");

            //给某个元素添加指定分数
            _redis.SortedSetIncrement(zsetkey, "马超", 1);
            //给某个元素减少指定分数
            _redis.SortedSetDecrement(zsetkey, "马超", 1);

            //获取某个分数段的元素
            var value1 = _redis.SortedSetRangeByScore(zsetkey, 50, 60);
            //获取某个分数段的元素及分数
            var value2 = _redis.SortedSetRangeByScoreWithScores(zsetkey, 50, 60);
            //获取某个排名段的元素
            var value3 = _redis.SortedSetRangeByRank(zsetkey, 0, 2);
            //获取某个排名段的元素及分数
            var value4 = _redis.SortedSetRangeByRankWithScores(zsetkey, 0, 2);
        }
        //[
        //    {
        //        "name":"刘备",
        //        "score":90
        //    },
        //    {
        //        "name":"张飞",
        //        "score":44
        //    },
        //    {
        //        "name":"关羽",
        //        "score":55
        //    },
        //    {
        //    "name":"赵云",
        //        "score":98
        //    },
        //    {
        //    "name":"马超",
        //        "score":41
        //    },
        //    {
        //    "name":"曹操",
        //        "score":91
        //    },
        //    {
        //    "name":"吕布",
        //        "score":55
        //    },
        //    {
        //    "name":"周瑜",
        //        "score":55
        //    },
        //]

        [HttpGet]
        public void ZSetTest()
        {
            //以上数据是该班级各同学的考试成绩，使用Zset数据类型添加到Redis数据库中，设置key为 "scorelist"
            var values = new[]
            {
                new SortedSetEntry("刘备", 90),
                new SortedSetEntry("张飞", 44),
                new SortedSetEntry("关羽", 55),
                new SortedSetEntry("赵云", 98),
                new SortedSetEntry("马超", 41),
                new SortedSetEntry("曹操", 91),
                new SortedSetEntry("吕布", 55),
                new SortedSetEntry("周瑜", 55),
            };
            _redis.SortedSetAdd("scorelist", values);
            //查询分数高的排名为第2 - 5名成绩的同学名单
            var value1 = _redis.SortedSetRangeByRank("scorelist", 1, 4, Order.Descending);

            //查询60分到100分的同学名单
            var value2 = _redis.SortedSetRangeByScore("scorelist", 60, 100);
        }

        /// <summary>
        /// 
        /// </summary>
        [HttpGet]
        public void SerializeJSON()
        {
            //查询商品
            var good = _db.Goods.FirstOrDefault(x => x.Id == 10);
            //转化为json字符串
            var jsonStr = JsonConvert.SerializeObject(good);
            //json字符串保存到redis
            _redis.StringSet("goodinfo", jsonStr);
            //从redis取出json字符串
            var redisStr = _redis.StringGet("goodinfo");
            //转化为对象
            var jsonObj = JsonConvert.DeserializeObject<Good>(redisStr);
        }

        /// <summary>
        /// 获取商品列表
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public List<Good> GetGoodList()
        {
            ////完成！！！ 使用本地缓存保存查询结果，缓存时间为30分钟
            ////1、先查看缓存有没有商品数据 key     变量类型和变量名
            //if (cache.TryGetValue("GoodCache", out List<Good> goodList)) {
            //    //3、如果有则直接返回缓存数据
            //    return goodList;
            //}
            //else {
            //    //2、如果没有则去数据库查询并且把查询结果保存到缓存 缓存时间为30分钟
            //    var goods = _db.Goods.ToList();
            //    cache.Set("GoodCache", goods, TimeSpan.FromMinutes(30));
            //    return goods;
            //}

            if (_redis.StringGet("GoodCache") == RedisValue.Null) {
                var goods = _db.Goods.ToList();
                var jsonStr = JsonConvert.SerializeObject(goods);
                _redis.StringSet("GoodCache", jsonStr, new TimeSpan(0, 30, 0));
                return goods;
            }
            else {
                return (JsonConvert.DeserializeObject<List<Good>>(_redis.StringGet("GoodCache")));
            }

        }


        /// <summary>
        /// 获取之前看过的商品
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public List<Good> GetGoodInfo(int goodId)
        {
            ////商品详情
            //var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);

            ////使用本地缓存保存登录用户浏览商品记录(多个商品)
            //var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            ////之前缓存下来的浏览记录  每个用户浏览记录都是单独的 每个用户都有自己的key  UserViews28\UserViews20
            //var record = cache.Get<List<Good>>($"UserViews{userId}");
            ////浏览商品记录
            //var views = new List<Good>();
            //views.Add(good); //永远只有刚刚看的这一条商品数据

            ////是不是还应该有前面的数据
            //if (record != null)
            //    views.AddRange(record); //我前面看过的数据

            //cache.Set($"UserViews{userId}", views);
            //return good;

            var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var record = new List<Good>();
            if (_redis.StringGet($"UserViews{userId}") != RedisValue.Null) {

                record = JsonConvert.DeserializeObject<List<Good>>(_redis.StringGet($"UserViews{userId}"));
            }
            var views = new List<Good>();
            views.Add(good);
            if (record != null) {
                views.AddRange(record);
            }

            //将list转换为string类型然后将其存在redis上
            var jsonStr = JsonConvert.SerializeObject(views);
            _redis.StringSet($"UserViews{userId}", jsonStr);
            return views;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public Good GetGoodInfo1(int goodId)
        {
            var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var key = $"UserViews{userId}";
            _redis.ListLeftPush(key, JsonConvert.SerializeObject(good));
            return good;
        }

        /// <summary>
        /// 添加商品进入购物车
        /// </summary>
        /// <param name="goodid"></param>
        //
        [HttpGet]
        [Authorize]

        public String AddCart(int goodid)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var hashkey = "car" + userId;
            _redis.HashIncrement(hashkey, goodid);
            return "添加成功";
        }

        /// <summary>
        /// 删除商品
        /// </summary>
        /// <param name="goodid"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public String defcart(int goodid)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var hashkey = "car" + userId;
            _redis.HashDelete(hashkey, goodid);
            return "删除成功";
        }


        /// <summary>
        /// 查询购物车商品
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public List<GetCarModel> Getcar()
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var hashKey = "car" + userId;
            var data = _redis.HashGetAll(hashKey);
            var list = new List<GetCarModel>();
            foreach (var item in data) {
                var good = _db.Goods.FirstOrDefault(x => x.Id == (int)item.Name);
                list.Add(new GetCarModel() {
                    GoodId = (int)item.Name,
                    Count = (int)item.Value,
                    Cover = good.Cover,
                    Name = good.Name,
                    Price = good.Price
                });
            }
            return list;

        }

        /// <summary>
        /// 添加热搜词语
        /// </summary>
        /// <param name="keyword"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public string AddKeyWord(string keyword)
        {
            var key = "hotkey";
            _redis.SortedSetIncrement(key, keyword, 1);
            return "添加成功";
        }


        /// <summary>
        /// 查询前10名热搜结果及搜索次数
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        public List<GetKeyWordModel> GetKeyWord()
        {
            var key = "hotkey";
            var data = _redis.SortedSetRangeByRankWithScores(key, 0, 9, Order.Descending);
            var list = new List<GetKeyWordModel>();
            foreach (var item in data) {
                list.Add(new GetKeyWordModel() {
                    KeyWord = (int)item.Element,
                    Count = item.Score
                });
            }
            return list;
        }


        [HttpGet]
        [Authorize]
        /// <summary>
        ///  关注用户用户
        /// </summary>
        /// <returns></returns>
        public string FollowUser(int followUserId)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var key = "follow_" + userId;
            _redis.SetAdd(key, followUserId);
            return "关注成功";
        }

        [HttpGet]
        [Authorize]
        /// <summary>
        ///  取消关注用户
        /// </summary>
        /// <returns></returns>
        public string UnFollowUser(int followUserId)
        {
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var key = "follow_" + userId;
            _redis.SetRemove(key, followUserId);
            return "取消关注成功";
        }

        /// <summary>
        /// 查看某个用户关注的人
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        [HttpGet]
        public List<int> GetFollowUserList(int userId)
        {
            var key = "follow_" + userId;
            var data = _redis.SetMembers(key);
            return data.Select(x => (int)x).ToList();
        }

        /// <summary>
        /// 获取两 个用户同时关注的人
        /// </summary>
        /// <param name="userId1"></param>
        /// <param name="userId2"></param>
        /// <returns></returns>
        [HttpGet]
        public List<int> GetFollowUserListIntersect(int userId1, int userId2)
        {
            var key = "follow_";
            var data = _redis.SetCombine(SetOperation.Intersect, key + userId1, key + userId2);
            return data.Select(x => (int)x).ToList();
        }


        /// <summary>
        /// 获取两个用户关注的用户总和
        /// </summary>
        /// <param name="userid1"></param>
        /// <param name="userid2"></param>
        /// <returns></returns>
        [HttpGet]
        public List<int> GetFollowUserListUnion(int userid1, int userid2)
        {
            var key = "follow_";
            var data = _redis.SetCombine(SetOperation.Union, key + userid1, key + userid2);
            return data.Select(x => (int)x).ToList();
        }
        //        当A进入B页面,求可能认识的人：这里指的是关注B中的用户 扣去 里面也关注A的用户，就是A可能认识的人。

        /// <summary>
        /// 用服务类查看用户浏览过的商品
        /// </summary>
        /// <param name="goodId"></param>
        /// <returns></returns>
        [HttpGet]
        [Authorize]
        public List<Good> GetUserGoodInfo(int goodId)
        {
            ////商品详情
            //var good = _db.Goods.FirstOrDefault(x => x.Id == goodId);

            ////使用本地缓存保存登录用户浏览商品记录(多个商品)
            //var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            ////之前缓存下来的浏览记录  每个用户浏览记录都是单独的 每个用户都有自己的key  UserViews28\UserViews20
            //var record = cache.Get<List<Good>>($"UserViews{userId}");
            ////浏览商品记录
            //var views = new List<Good>();
            //views.Add(good); //永远只有刚刚看的这一条商品数据

            ////是不是还应该有前面的数据
            //if (record != null)
            //    views.AddRange(record); //我前面看过的数据

            //cache.Set($"UserViews{userId}", views);
            //return good;

            var good = _userService.GetGoodByGoodId(goodId);
            var userId = Response.HttpContext.User.Claims.FirstOrDefault(x => x.Type == ClaimTypes.NameIdentifier).Value;
            var record = new List<Good>();
            if (_redis.StringGet($"UserViews{userId}") != RedisValue.Null) {

                record = _userService.selectUserHistory($"UserViews{userId}");
            }


            //var views = new List<Good>();
            //views.Add(good);
            //if (record != null) {
            //    views.AddRange(record);
            //}
            ////
            //var jsonStr = JsonConvert.SerializeObject(views);
            //_redis.StringSet($"UserViews{userId}", jsonStr);
            var views = _userService.AddUserHistory(record, good, $"UserViews{userId}");
            return views;
        }

    }
}
